package montecarloMulti;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;



public class ModelMultiThreads {
	
	
    public double monteCarloStandardOption(String callPutFlag, Double S,Double X,Double T,Double r,Double b,Double v,int nSteps,int nSimulation) throws InterruptedException, ExecutionException{
       
	    Double dt;
	  //Double St ;
	    Double sum=0.0;
	    Double drift;
	    Double vSqrdt;
	    Double toReturn;
        
	    int i;
	  //int j;
	    int z=0;
        
        dt = T / nSteps;
        drift = (b - v*v / 2) * dt;
        vSqrdt = v * Math.sqrt(dt);
        
        if(callPutFlag.equals("c")){z=1;}
        else if(callPutFlag.equals("p")){z=-1;}
       
        
        List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
        
        for(i=1;i<=nSimulation;i++){
        	 
        	partitions.add(new Mycallable(S,nSteps,drift,vSqrdt));
        	
        }
         
        //int poolSize=(int)(Runtime.getRuntime().availableProcessors()/(1-0.7)); //donne la poolsize
        
        int poolSize=20;
        
        System.out.println("pool size "+poolSize);
        
        ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);    //cree la ps avec le bon nb de threads determin�s
        
        List<Future<Double>> valueOfStocks = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS); //demare la pool et cre� la liste de resultat
       
        executorPool.shutdown(); //ferme la pool
          
       
        for(Future<Double> valueOfAStock : valueOfStocks) { 
        	sum = sum + Math.max(z*(valueOfAStock.get()-X),0);    // je somme tt les resultat
        }
        
        
        toReturn=Math.exp(-r*T)*(sum/nSimulation);                
        return toReturn;
   
    } 
    
    private class Mycallable implements Callable<Double>{           
    
    	private double S;
    	private double nSteps;
    	private double drift;
    	private double vSqrdt;
    	
    	
    	
    	
    public Double call(){             // en gros c'est c'est un runnable de thread
    
    Double St=S;
    Random random = new Random();
    
    for(int j=1;j<=nSteps;j++){
        St = St * Math.exp(drift + vSqrdt * random.nextGaussian());
    }
    return St;
    }
    
    Mycallable(double S,double nSteps, double drift,double vSqrdt){
    	
    	 this.S=S;
    	 this.nSteps=nSteps;
    	 this.drift=drift;
    	 this.vSqrdt=vSqrdt;
    	
    }
    }
    
    public static ArrayList<ArrayList> readFile() throws FileNotFoundException, IOException{
        String FILE_NAME = "parameters.csv";

        File file = new File(FILE_NAME);
        StringTokenizer lineParser; 
        BufferedReader reader = new BufferedReader(new FileReader(file));
        ArrayList<ArrayList> dataTable = new ArrayList<ArrayList>(); 
        ArrayList<String> dataRow; 
        String line = null; 
        String value = null;
        
        while ((line = reader.readLine()) != null) { 
            dataRow = new ArrayList<String>(); 
            lineParser = new StringTokenizer(line, ";"); 
            while (lineParser.hasMoreElements()) { 
                value = (String) lineParser.nextElement(); 
                dataRow.add(value); 
            } 
        dataTable.add(dataRow); 
        }
        return dataTable;
    }
}
